home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Pascal Super Library
/
Pascal Super Library (CW International)(1997).bin
/
COMM
/
RPL60
/
RPL.PAS
< prev
next >
Wrap
Pascal/Delphi Source File
|
1992-12-31
|
24KB
|
712 lines
{$A+,B+,E-,F-,I+,L+,N-,O-,R-,S-,V-} { TP6 Compiler Options }
{$M 65500,65500,655000}
{*source code copyright (c) 1985, by TurboPower Software*}
{ "UpGraded" to compile under TP6.0 by Steve Whalen 3-16-92 }
program Rpl;
{-select text lines, match and replace strings}
uses
{ Mon, }
OpCrt,
Dos,
OpDos,
OpString; { for UpCaseMac }
const
Copyright : String[79] = 'RPL - Pattern Replacer. Copyright (c) 1985 by TurboPower Software.';
Version : String[79] = 'All Rights Reserved. Version 1.21.60b';
OptionDelim = '-'; {character used to introduce a command line option}
Null = #00;
EndStr = #255;
NewLine = #13#10;
Dash = '-';
Esc = '\';
Any = '?';
Closure = '*';
ClosurePlus = '+';
MaybeOne = '!';
Bol = '^';
Eol = '$';
Ccl = '[';
Negate = '^';
CclEnd = ']';
BTag = '{';
ETag = '}';
BGroup = '(';
EGroup = ')';
Alter = '#';
Ditto = '&';
lSpace = 's';
lNewline = 'n';
lTab = 't';
lBackSpace = 'b';
lReturn = 'r';
lFeed = 'l';
lHex = 'h';
lWordDelim = 'w';
lInput = 'i';
lOutput = 'o';
lPipe = 'p';
lNil = 'z';
wDelimString = #9#32'!"&()*+,-./:;<=>?@[\]^`{|}~';
LabLen = 1024;
TokLen = 255; {max length of a command line token}
MaxTok = 10; {max number of tokens on command line}
BufLen = 16384;
LowMono = LightGray;
HighMono = White;
LowColor = Cyan;
HighColor = Yellow;
type
FileType = Text;
Line = record
Length : Integer;
Val : array[1..LabLen] of Char;
end;
BufLine = array[1..BufLen] of Char;
LongString = String[255];
PatLine = String[255];
Tokens = (tNil, tLitChar, tCcl, tnCcl, tClosure, tMaybeOne,
tAny, tBol, tEol, tGroup, tbTag, teTag, tDitto);
PatPtr = ^PatRecord;
lsPtr = ^LongString;
PatRecord = record
Tok : Tokens;
One : Char;
NexTok : Boolean;
StrPtr : lsPtr;
NestPtr, Next : PatPtr;
end;
TagLevel = -1..9;
Flag = array[1..LabLen] of TagLevel;
FileString = String[64];
RegPack = Registers;
Token = String[TokLen];
ArgArray = array[1..MaxTok] of Token;
Message = String[79];
var
argc : Integer; {argument count (number of tokens)}
argv : ArgArray; {elements are the tokens found on the command line}
ErrMess : Message; {error message, if any, returned from getcom}
Path, Out1, Out2 : LongString;
Rep, Sel, Pat : PatLine;
OutLine : Line;
SelRec, PatRec, RepRec : PatPtr;
CinF : FileType;
ConsoleIn, ConsoleOut, FileOpen, Matching, Monly, UnSelOut,
ShowLines, IgnoreCase, Debug, ShowStatus, InterActive,
InputOpen, CountOnly, Avoiding, Selecting, Replacing : Boolean;
Reg : RegPack;
InHandle, SelectCnt, MatchCnt, wrCnt, ScreenLine,
lNum, OutHandle : Integer;
tStart, tStop, Rate : Real;
nStr : String[6];
{$I rpllow.inc}
{$I rplfind.inc}
{$I rplpat.inc}
{$I rplmat.inc}
{$I rplrep.inc}
{$I RplHelp.Inc}
procedure ParseCommand(UsePsp : Boolean; cLine : LongString);
{-interpret a command line to get options and templates}
var
tLine : LongString;
i : Integer;
c : Char;
cfName : FileString;
HaltSoon, cFileToRead, OK : Boolean;
begin
OK := True;
if not(UsePsp) then OK := GetCom(UsePsp, cLine, ErrMess);
if OK and (argc > 0) then begin
HaltSoon := False;
cFileToRead := False;
i := 1;
while i <= argc do begin
if argv[i][1] = OptionDelim then begin
{start of a command option}
c := UpCaseMac(argv[i][2]);
{make sure it really is meant to be a command}
if (c <> 'O') and (c <> 'U') then begin
if Length(argv[i]) <> 2 then begin
WrL('unrecognized command option '+argv[i]);
HaltSoon := True;
end;
end else begin
if Length(argv[i]) <> 3 then begin
WrL('unrecognized command option '+argv[i]);
HaltSoon := True;
end;
end;
case c of
'?' : WriteHelp;
'I' : IgnoreCase := True;
'N' : ShowLines := True;
'F' : begin {finding a command file -- note nesting OK}
i := Succ(i);
if i <= argc then OK := True else OK := False;
if OK then begin
cFileToRead := True;
cfName := argv[i];
DefaultExtension('PAT', cfName);
end else begin
WrL('improper command file specification '+argv[Pred(i)]);
HaltSoon := True;
end;
end;
'U' : begin {unselected lines}
c := UpCaseMac(argv[i][3]);
if c = 'S' then UnSelOut := True
else begin
WrL('unrecognized command option '+argv[i]);
HaltSoon := True;
end;
end;
'O' : begin {output selection option}
c := UpCaseMac(argv[i][3]);
case c of
'M' : Monly := True;
'C' : CountOnly := True;
else
WrL('unrecognized output selector -O'+c);
HaltSoon := True;
end;
end;
'S' : begin {selection pattern follows}
if not(Avoiding) then begin
Selecting := True;
i := Succ(i);
if i <= argc then Sel := argv[i]+EndStr else begin
WrL('didn''t find select pattern');
Halt;
end;
end;
end;
'V' : begin
if not(Selecting) then begin
Avoiding := True;
i := Succ(i);
if i <= argc then Sel := argv[i]+EndStr else begin
WrL('didn''t find select pattern');
HaltSoon := True;
end;
end;
end;
'M' : begin
Matching := True;
i := Succ(i);
if i <= argc then Pat := argv[i]+EndStr else begin
WrL('didn''t find match pattern');
HaltSoon := True;
end;
end;
'R' : begin
Replacing := True;
i := Succ(i);
if i <= argc then Rep := argv[i]+EndStr else begin
{it must specify a null replace pattern}
Rep := EndStr;
end;
end;
'D' : Debug := True;
else
WrL('unrecognized command option -'+c);
HaltSoon := True;
end;
end else begin
if argv[i] = '?' then begin
WriteHelp;
end else begin
{must be a file specification}
{IF consolein AND NOT(inputopen) THEN BEGIN}
{ignore it if another file is already open}
OpenFile(argv[i], InHandle);
{map it onto the standard input}
ForceDup(InHandle, 0);
CloseFile(InHandle);
InputOpen := True;
InHandle := 0;
{END;}
end;
end;
i := Succ(i);
end;
{read a command file if called for}
if cFileToRead then begin
OK := FoundFile(cfName, Path, CinF);
if OK then begin
ReadLn(CinF, tLine);
Close(CinF);
ParseCommand(False, tLine);
end;
end;
{build tokenized patterns, only after all command files are read}
if UsePsp or InterActive then begin
if Selecting and (SelRec = nil) then
if not(GetPat(Sel, SelRec)) then begin
WrL('bad select pattern: '+Sel);
HaltSoon := True;
end;
if Avoiding and (SelRec = nil) then
if not(GetPat(Sel, SelRec)) then begin
WrL('bad avoid pattern: '+Sel);
HaltSoon := True;
end;
if Matching and (PatRec = nil) then
if not(GetPat(Pat, PatRec)) then begin
WrL('bad match pattern: '+argv[i]);
HaltSoon := True;
end;
if Replacing and (RepRec = nil) then
if not(GetRep(Rep, RepRec)) then begin
WrL('bad replace pattern: '+argv[i]);
HaltSoon := True;
end;
{check for errors}
if not(Matching or Selecting or Avoiding) then begin
WrL('must specify at least a match, select or avoid pattern');
HaltSoon := True;
end;
if ConsoleIn and not(InputOpen) then begin
WrL('must specify an input file');
HaltSoon := True;
end;
if Replacing and not(Matching) then begin
WrL('if a replace pattern is specified, a match pattern must also be entered');
HaltSoon := True;
end;
{don't get putl confused}
if CountOnly then ShowLines := False;
end;
end else begin
WrL('must specify at least a match or select pattern');
HaltSoon := True;
end;
if HaltSoon then begin
if InputOpen then CloseFile(InHandle);
WrL('type RPL -? for help');
Halt;
end;
end; {parsecommand}
procedure GetInputs;
{-prompt for inputs}
label 1;
var
fName : FileString;
ComFile, Done : Boolean;
cLine : PatLine;
c : Char;
function RealDiskFile(var fName : FileString; var UseConsole : Boolean) : Boolean;
{-return true if fname is a disk file and not a device}
{-not strictly accurate but consistent with DOS behavior}
const
NumDevs = 22; {!!! .60b ... added Com3 & Com4 }
DevNames : array[1..NumDevs] of String[5] =
('LPT1', 'LPT2', 'LPT3', 'AUX', 'COM1', 'COM2', 'COM3', 'COM4', 'PRN', 'CON', 'NUL',
'LPT1:', 'LPT2:', 'LPT3:', 'AUX:', 'COM1:', 'COM2:', 'COM3:', 'COM4:', 'PRN:', 'CON:', 'NUL:');
var
i, l : Byte;
tName : FileString;
begin
RealDiskFile := True;
UseConsole := False;
i := Pos('.', fName);
if i > 0 then tName := Copy(fName, 1, Pred(i)) else tName := fName;
l := Length(tName);
for i := 1 to l do tName[i] := UpCaseMac(tName[i]);
i := 1;
while i <= NumDevs do begin
if tName = DevNames[i] then begin
RealDiskFile := False;
UseConsole := (DevNames[i] = 'CON') or (DevNames[i] = 'CON:');
{remove colon if at end of name}
if tName[l] = ':' then fName := Copy(tName, 1, Pred(l)) else fName := tName;
i := NumDevs;
end;
i := Succ(i);
end;
end; {realdiskfile}
function CheckPat(Pat : PatLine; var PatRec : PatPtr) : Boolean;
{-build match pattern and return true if ok}
begin
if GetPat(Pat, PatRec) then begin
CheckPat := True;
end else begin
WrL('bad match pattern. try again....');
CheckPat := False;
end;
end; {checkpat}
begin
InterActive := True;
1:
if ConsoleIn then begin
Wr('Enter name of input text file: ');
ReadLn(fName);
if fName = '' then Halt;
OpenFile(fName, InHandle);
{map it onto the standard input}
ForceDup(InHandle, 0);
CloseFile(InHandle);
InputOpen := True;
InHandle := 0;
end;
WrL('');
Wr('Do you want to read a command line file? (Y/N, <cr> for N) ');
ComFile := ReadYesNo(False);
if ComFile then begin
WrL('');
repeat
Wr('Enter name of command line file: ');
ReadLn(fName);
if Length(fName) > 0 then begin
DefaultExtension('PAT', fName);
end else Halt;
Done := FoundFile(fName, Path, CinF);
until Done;
ReadLn(CinF, cLine);
Close(CinF);
ParseCommand(False, cLine);
end else begin
{no command line file}
WrL('');
Wr('Do you want to specify a select criterion? (Y/N, <cr> for N) ');
Selecting := ReadYesNo(False);
if not(Selecting) then begin
WrL('');
Wr('Do you want to specify an avoid criterion? (Y/N, <cr> for N) ');
Avoiding := ReadYesNo(False);
end;
if Avoiding or Selecting then begin
WrL('');
repeat
Wr('enter select/avoid expression: ');
ReadLn(Pat);
if Length(Pat) = 0 then Halt;
Pat := Pat+EndStr;
Done := CheckPat(Pat, SelRec);
until Done;
WrL('');
Wr('Do you want to output non-selected lines? (Y/N, <cr> for N) ');
UnSelOut := ReadYesNo(False);
WrL('');
Wr('Do you want to specify a match criterion? (Y/N, <cr> for Y) ');
Matching := ReadYesNo(True);
end;
if Matching or not(Selecting or Avoiding) then begin
WrL('');
repeat
Wr('enter match expression: ');
ReadLn(Pat);
if Length(Pat) = 0 then Halt;
Pat := Pat+EndStr;
Done := CheckPat(Pat, PatRec);
Matching := True;
until Done;
end;
if Matching then begin
WrL('');
Wr('Do you want to do replacements? (Y/N, <cr> for Y) ');
Replacing := ReadYesNo(True);
if Replacing then begin
WrL('');
repeat
Wr('enter replace expression: ');
ReadLn(Rep);
Rep := Rep+EndStr;
if GetRep(Rep, RepRec) then begin
Done := True;
if Debug then begin
Wr('replace pattern: '); WritePat(RepRec); WrL('');
end;
end else begin
WrL('bad replace pattern. try again....');
Done := False;
end;
until Done;
WrL('');
Wr('Do you want to output only modified lines? (Y/N, <cr> for N) ');
Monly := ReadYesNo(False);
end;
end;
WrL('');
Wr('Do you want to output only the matched line count? (Y/N, <cr> for N) ');
CountOnly := ReadYesNo(False);
if not(CountOnly) then begin
WrL('');
Wr('Do you want to show line numbers on output lines? (Y/N, <cr> for N) ');
ShowLines := ReadYesNo(False);
end;
end;
if ConsoleOut then begin
{output has not already been redirected}
WrL('');
Wr('Enter file name where output will be sent (<cr> for screen): ');
ReadLn(fName);
if Length(fName) > 0 then begin
{open for writing -- we don't check for overwrite}
FileOpen := RealDiskFile(fName, ConsoleOut);
CreateFile(fName, OutHandle);
end; {outhandle defaults to 1 (standard output)}
end;
WrL('');
Wr('OK to proceed? (Y/N) ');
repeat
c := ReadKey;
c := UpCaseMac(c);
until (c in ['Y', 'N']);
WrL(c);
WrL('');
if c = 'N' then begin
if FileOpen then CloseFile(OutHandle);
goto 1;
end;
end; {getinputs}
procedure ProcessLine(Lin : Line);
{-process an input line and send to output}
var
mLin, Sub : Line;
GoodLine : Boolean;
Temp : String[2];
begin
lNum := Succ(lNum);
if lNum < 0 then lNum := 0;
{ IF breakpressed THEN breakhalt; }
if ShowStatus and ((lNum mod 8) = 0) then begin
Wr(^H^H^H^H^H^H+LongIntForm('######', lNum));
end;
Temp := NewLine;
AppendS(Lin.Val, Lin.Length, Temp[1], 2, Lin);
Temp := EndStr;
AppendS(Lin.Val, Lin.Length, Temp[1], 1, mLin);
if Selecting then begin
GoodLine := Match(mLin, SelRec);
end else if Avoiding then begin
GoodLine := not(Match(mLin, SelRec));
end else GoodLine := True;
if GoodLine then begin
{met select criterion, perhaps by default}
SelectCnt := Succ(SelectCnt);
if Replacing then begin
if Monly then begin
{we only want to replace and output lines that have a match}
GoodLine := Match(mLin, PatRec);
end;
if GoodLine then begin
SubLine(mLin, PatRec, RepRec, Sub);
if not(CountOnly) then PutL(Sub);
{subline keeps a count of matched lines and replaced patterns}
end;
end else if Matching then begin
GoodLine := Match(mLin, PatRec);
{met match criterion}
if GoodLine then begin
MatchCnt := Succ(MatchCnt);
if not(CountOnly) then PutL(Lin);
end;
end else begin
{we are neither matching nor replacing, just selecting}
{output the selected line}
if not(CountOnly) then PutL(Lin);
end;
end else begin
{non-selected line, do we print it?}
if UnSelOut and not(CountOnly) then PutL(Lin);
end;
end; {processline}
procedure GetFromFile;
{-read chunks from a file, process and send to standard output}
var
c : Char;
Done : Boolean;
l : Line;
lt : array[0..1] of BufLine;
lCount : array[0..1] of Integer;
lStart, InExt, i, lPos : Integer;
begin
InExt := 0; lStart := 0; ScreenLine := 1;
repeat
{get a new chunk}
Done := GetChunk(lt[InExt], lCount[InExt]);
{build a line terminated by CR/LF, EOF, or max length}
i := 1; lPos := lStart;
while i <= lCount[InExt] do begin
c := lt[InExt][i];
if c = #13 then begin
{found the end of a line}
l.Length := lPos;
ProcessLine(l);
lPos := 0;
end else if c = #26 then begin
{found end of file marker}
l.Length := lPos;
if lPos > 0 then ProcessLine(l);
Done := True;
i := LabLen;
end else if c <> #10 then begin
if lPos < LabLen then begin
{append this character to current line}
{ignore characters beyond the limit of length}
lPos := Succ(lPos);
l.Val[lPos] := c;
end else begin
if ShowStatus then begin
Wr(^m);
end else begin
WrL(''); WrL('');
end;
WrL('WARNING: line '
+LongIntForm('######', Succ(lNum))+' exceeds '
+Long2Str(LabLen)+' characters. Line broken...');
WrL('');
if ShowStatus then begin
Wr('line number: '+LongIntForm('######', Succ(lNum)));
end;
l.Length := lPos;
ProcessLine(l);
lPos := 0;
end;
end;
i := Succ(i);
end;
InExt := 1-InExt; {switch to the other temporary line}
lStart := lPos; {continue the line being built}
if Done and (c <> #26) and (c <> #13) and (c <> #10) then begin
{last line of file did not end with #26 or #13}
l.Length := lPos;
ProcessLine(l);
end;
until Done;
end; {getfromfile}
(*
procedure WriteDebug;
{-display the global flags and settings}
begin
if Matching then begin
Wr('mat: '); WritePat(PatRec); WrL('');
end;
if Replacing then begin
Wr('rep: '); WritePat(RepRec); WrL('');
end;
if Selecting or Avoiding then begin
Wr('sel: '); WritePat(SelRec); WrL('');
end;
WriteLn('sel: ', Selecting, ' avo: ', Avoiding, ' mat: ', Matching, ' rep: ', Replacing);
WriteLn(' conout: ', ConsoleOut, ' conin: ', ConsoleIn, ' inopen: ', InputOpen);
WriteLn('cnt: ', CountOnly, ' outhand: ', OutHandle, ' inhand: ', InHandle);
WrL('');
end; {WriteDebug}
*)
begin
CheckBreak := True;
DirectVideo := False;
TextBackGround(Black);
HiVid;
WrL('');
{set defaults}
OutHandle := 1; FileOpen := False; InHandle := 0;
Selecting := False; Avoiding := False;
Matching := False; Replacing := False;
ShowLines := False; CountOnly := False; IgnoreCase := False;
UnSelOut := False; Monly := False; Debug := False;
lNum := 0; MatchCnt := 0; SelectCnt := 0; wrCnt := -32766;
SelRec := nil; PatRec := nil; RepRec := nil; InterActive := False;
ConsoleOut := IoStat(1);
ConsoleIn := IoStat(0);
InputOpen := not(ConsoleIn);
{get inputs}
if GetCom(True, '', ErrMess) then begin
if argc > 0 then ParseCommand(True, '') else GetInputs;
{reassure that the input was read right}
{if Debug then WriteDebug;}
tStart := TimeMs/1000; { !!!.60b } { convert Msec to Seconds }
ShowStatus := not(ConsoleOut) or CountOnly;
if ShowStatus then begin
Wr('line number: '+' 1');
end;
{read the input file, perform matching, and Wr output}
GetFromFile;
tStop := TimeMs/1000; { !!!.60b } { convert Msec to Seconds }
if ShowStatus then begin
Wr(^m);
end else begin
WrL('');
end;
WrL('lines input: '+Long2Str(lNum)+' lines selected: '+Long2Str(SelectCnt));
Wr('lines matched: '+Long2Str(MatchCnt)+' patterns replaced: ');
if wrCnt >= 32766 then
WrL('> 32766')
else
WrL(Long2Str(wrCnt+32766));
if (tStop-tStart) > 0 then begin
Rate := lNum/(tStop-tStart);
WrL('scan rate: '+Form('####.#', Rate)+' LPS');
end;
WrL('');
if CountOnly and not(ConsoleOut) then begin
WrL('');
Str(SelectCnt, nStr);
Out1 := '#lines selected: '+nStr;
Str(MatchCnt, nStr);
Out2 := ' #lines matched: '+nStr;
AppendS(Out1[1], Length(Out1), Out2[1], Length(Out2), OutLine);
Str((Int(wrCnt)+32766.0):5:0, nStr);
Out1 := ' #patterns replaced: ';
if wrCnt = 32766 then Out1 := Out1+'>';
Out1 := Out1+nStr+#13+#10;
AppendS(OutLine.Val, OutLine.Length, Out1[1], Length(Out1), OutLine);
PutL(OutLine);
end;
if not(ConsoleOut) or FileOpen then begin
ShowLines := False; {don't print a line number with EOF}
(*
outline.val[1] := ^Z; {choice of whether to end with ^Z or not}
outline.length := 1;
putl(outline);
*)
CloseFile(OutHandle);
end;
if InputOpen then CloseFile(InHandle);
end else WrL(ErrMess);
end. {rpl}